package my.android;

import android.app.Activity;
import android.content.Context;
import android.graphics.Matrix;
import android.os.Bundle;
import android.util.FloatMath;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.ImageView;

public class AndroidImagePanZoomActivity extends Activity implements
        OnTouchListener {
    // matrices holding old and current transformation status
    Matrix oldMatrix = new Matrix();
    Matrix currentMatrix = new Matrix();
    // possible touch states
    final static int NONE = 0;
    final static int DRAG = 1;
    final static int ZOOM = 2;
    int touchState = NONE;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);     
//        Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); 
//        int width = display.getWidth(); 
//        int height = display.getHeight();
        ImageView view = (ImageView) findViewById(R.id.imageView);
//        view.setPadding(width/2, height/2, 0, 0);
        
        if (view.getImageMatrix() != null)
            oldMatrix.set(view.getImageMatrix());
        view.setOnTouchListener(this);
    }
    
    final static float MIN_DIST = 50;
    static float eventDistance = 0;
    static float centerX = 0, centerY = 0;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        ImageView view = (ImageView) v;
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            // primary touch event starts: remember touch down location
            touchState = DRAG;
            centerX = event.getX(0);
            centerY = event.getY(0);
            if (view.getImageMatrix() != null)
                oldMatrix.set(view.getImageMatrix());
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            // secondary touch event starts: remember distance and center
            eventDistance = calcDistance(event);
            calcMidpoint(event);
            if (eventDistance > MIN_DIST) {
                touchState = ZOOM;
                if (view.getImageMatrix() != null)
                    oldMatrix.set(view.getImageMatrix());
            }
            break;
        case MotionEvent.ACTION_MOVE:
            if (touchState == DRAG) {
                // single finger drag, translate accordingly
                currentMatrix.set(oldMatrix);
                currentMatrix.postTranslate(event.getX(0) - centerX,
                        event.getY(0) - centerY);

            } else if (touchState == ZOOM) {
                // double-finger zoom, scale accordingly around center
                float dist = calcDistance(event);
                if (dist > MIN_DIST) {
                    currentMatrix.set(oldMatrix);
                    float scale = dist / eventDistance;
                    currentMatrix.postScale(scale, scale, centerX, centerY);
                }
            }
            // perform transformation
            view.setImageMatrix(currentMatrix);
            break;
        case MotionEvent.ACTION_UP:
            touchState = NONE;
            // save matrix
            oldMatrix.set(view.getImageMatrix());
            break;
        case MotionEvent.ACTION_POINTER_UP:
            touchState = DRAG;
            // save matrix
            oldMatrix.set(view.getImageMatrix());
            // update touch down location for drag event to holding finger
            switch (event.getActionIndex()) {
            case 0:
                centerX = event.getX(1);
                centerY = event.getY(1);
                break;
            case 1:
                centerX = event.getX(0);
                centerY = event.getY(0);
                break;
            }
            break;
        }
        return true;
    }

    private float calcDistance(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return FloatMath.sqrt(x * x + y * y);
    }

    private void calcMidpoint(MotionEvent event) {
        centerX = (event.getX(0) + event.getX(1)) / 2;
        centerY = (event.getY(0) + event.getY(1)) / 2;
    }
}
